package tools;

import util.Memorier;


public abstract class Matrix<T>{
	
	protected int ln;
	protected int cl;
	protected T[][] mtx;
	protected Memorier mem;
	
	protected abstract T define0();
	protected abstract T defineSum(T elem1, T elem2);
	protected abstract T defineProduct(T elem1, T elem2);
	protected abstract T defineSub(T elem1, T elem2);
	
	public Matrix(int ln, int cl){
		this.ln = ln;
		this.cl = cl;
		mem = new Memorier();
		mem.addLongSize(2);
	}
	
	public void set(int i, int j, T value){
		mtx[i][j] = value;
	}

	public T get(int i, int j){
		return mtx[i][j];
	}
	
	public abstract Vector<T> getLine(int i);
	
	public abstract Vector<T> getColumn(int i);
	
	public double memoryUsedB(){
		double m = mem.getUsedMemB();
		return m;
	}
	
	public double memoryUsedKB(){
		double m = mem.getUsedMemKB();
		return m;
	}
	
	public double memoryUsedMB(){
		double m = mem.getUsedMemMB();
		return m;
	}

	public abstract Matrix<T> copy();


	public Matrix<T> sum(Matrix<T> M) {
		Matrix<T> copy = copy();
		for(int  i = 0; i < ln; i++){
			for(int j = 0; j < cl; j++){
				copy.set(i, j, defineSum(get(i,j), M.get(i, j)));
			}
		}
		return copy;
	}
		
	public Matrix<T> sub(Matrix<T> M) {
		Matrix<T> copy = copy();
		for(int  i = 0; i < ln; i++){
			for(int j = 0; j < cl; j++){
				copy.set(i, j, defineSub(get(i,j), M.get(i, j)));
			}
		}
		return copy;
	}
	
	public Matrix<T> prod(Matrix<T> M) {
		Matrix<T> copy = copy();
		T accum = define0();
		for(int  i = 0; i < ln; i++){
			for(int j = 0; j < cl; j++){
				accum = define0();
				for(int k = 0; k < cl; k++){
					accum = defineSum(accum, defineSum(get(i,k), M.get(k, j)));
				}
				copy.set(i,j, accum);
			}
		}
		return copy;
	}
	
	public abstract Matrix<T> transposition();
	
	public T trace(){
		T rest = define0();
		for(int i = 0; i < ln; i++){
			rest = defineSum(rest, get(i,i));
		}
		return rest;
	}
}
